package sjtu.ist.warehouse4ws.tool;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Stack;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

import sjtu.ist.warehouse4ws.epc2bpmn.GenerateBpmn;
import sjtu.ist.warehouse4ws.epc2bpmn.ParserEpc;
import sjtu.ist.warehouse4ws.model.Epcunit;
import sjtu.ist.warehouse4ws.model.Epcunits;

public class GenerateBpel {


	    private Epcunits unitList=null;
	 
	    public Epcunits getUnitList() {
			return unitList;
		}

		public void setUnitList(Epcunits unitList) {
			this.unitList = unitList;
		}
		public HashMap<String,String> fs;

		public HashMap<String, String> getFs() {
			return fs;
		}

		public void setFs(HashMap<String, String> fs) {
			this.fs = fs;
		}
		public  List<Epcunit> polishBPELModelsWithLoop(
	            List<Epcunit> sourceList) {
			List<Epcunit> dfsList=new ArrayList<Epcunit>();
			Hashtable<Epcunit,Integer> isTraversed=new Hashtable();//存储已访问的单元
			for (Epcunit temp:sourceList){
				isTraversed.put(temp,0);
			}
			Epcunits uList=new Epcunits();
			uList.setEpcUnits(sourceList);
	    	this.setUnitList(uList);
	    	int max=unitList.findMaxId();   //流程最大id
	    	
	    	
	    		
	        while (true) {
	            Epcunit xor = null;
	            for (Epcunit unit :unitList.getEpcUnits()) {  
	            	if (unit.getType()=="connector"
	                        && unit.getName()=="xor"
	                        && unit.getNext().size() > 1
	                        && isTraversed.get(unit)!=1)
	                {
	                    xor = unit;  
	                    isTraversed.put(unit,1);  //标记xor已访问
	                    break;
	                }
	                   isTraversed.put(unit, 1);
	            }     //找到流程中第一个未被访问的xor点
	           
	           
	            if (xor == null) {
	            	
	                break;
	            }

	           
	            List<Integer> next=xor.getNext();
	            for (Integer n1=0; n1<next.size();n1++) {
	            	
	                Epcunit startUnit =unitList.findSourceDataById(next.get(n1));
	                
	                Epcunit nextUnit=startUnit;   //遍历流程的指针
	                Epcunit entranceUnit = startUnit; //标记循环的开始结点
	                boolean isLoop = false;
	               while(true){
	            	   if (nextUnit.getNext().toString()=="[]") {
	                        break;
	                    } else if (nextUnit.getType()=="connector") {
	                        
	                        if (isTraversed.get(nextUnit)==1) {           //如果访问到已访问过的连接符
	                            isLoop = true;
	                        }
	                        break;
	                       
	                    } else {
	                    	for (Integer n2:nextUnit.getNext()){
	                    		nextUnit=unitList.findSourceDataById(n2);
	                    		
	                    		break;
	                    	}
	                    }
	                                 //判断xor 是否有环路
	            	   
	               } 
	                
	                   
	                     
	                
	                
	                
	                if (isLoop) {
	                    List<Epcunit> funcList = new ArrayList<Epcunit>();
	                    List<Epcunit> tempList = new ArrayList<Epcunit>();
	                   
	                   
	                    // find entrance function of the loop
	                    boolean tempbool = false;
	                    Epcunit searchUnit = startUnit;
	                    Epcunit preUnit = searchUnit;
	                    Epcunit lastUnit= null;
	                    while (true) {
	                    	
	                    	 
	                    	if (unitList.findSource(searchUnit).size()==1){
	                    		 if (searchUnit.getType()=="function" && tempbool==true) 
	 	                            funcList.add(searchUnit);
	                    		  else if (tempbool==false && searchUnit.getType()=="function")
	  	                        	tempList.add(searchUnit);
	                    		
	                    	}
	                        else if (unitList.findSource(searchUnit).size()>1){
	                        	tempbool= true;
	                            lastUnit=preUnit;
	                        	entranceUnit=searchUnit;    //循环结构的初始结点
	                        	if (searchUnit.getType()=="function") funcList.add(searchUnit); 
	                        } 
	                        if (searchUnit.getType()== "connector") {
	                        	break;
	                        }
	                    	
	                        for (Integer n3:searchUnit.getNext()){
	                        	 preUnit=searchUnit;   //循环结构的最后一个结点
	                        	 searchUnit= unitList.findSourceDataById(n3);  
	                        	 break;
	                        	 
	                        }

	                    }    
	                    funcList.addAll(tempList);//保存循环结构function
	                    
	                    
	                   
	                    Epcunit prefixUnit = null;
	                    Epcunit postfixUnit = null;
	                    int preIndex=unitList.getEpcUnits().indexOf(lastUnit);
	                    List<Epcunit> sList=unitList.findSource(entranceUnit);
	                    for (Epcunit e:sList){
	                        if (preIndex>unitList.getEpcUnits().indexOf(e) && e!=lastUnit)	
	                    	     preIndex=unitList.getEpcUnits().indexOf(e);
	                    }
	                    
	                    prefixUnit=unitList.getEpcUnits().get(preIndex); //循环结构前的结点
	                   
	                    unitList.removeRelationship(prefixUnit, entranceUnit);//删除循环结构的 循环连接
	                    Epcunit xorTemp=new Epcunit();  //避免与xor冲突 设置一个拷贝对象
	                    xorTemp.setNext(xor.getNext());
	                    for (int n4:xorTemp.getNext()){
	                    	postfixUnit=unitList.findSourceDataById(n4);
	                    	if (postfixUnit!=startUnit){
	                    		unitList.removeRelationship(xor, postfixUnit);     //标记循环结构的结束结点 并删除与XOR的连接
	                    		break;
	                    	}
	                    		 
	                    }                   

	             

	                    // Remove all relationships from function units.
	                    for (Epcunit func : funcList) {
	                       func.getNext().clear();             
	                    }

	                    // 把循环结构中的结点串起来
	                   
	                    if (funcList.size() != 0) {
	                    	
	                        Epcunit whileStart = new Epcunit();
	                        whileStart.setName("WHILE_START");
	                        whileStart.setType("while");
	                        max++;
	                        isTraversed.put(whileStart,1);
	                        whileStart.setId(max);
	                        Epcunit whileEnd = new Epcunit();
	                        whileEnd.setName("WHILE_END");
	                        whileEnd.setType("while");
	                        max++;
	                        whileEnd.setId(max);
	                        isTraversed.put(whileEnd,1);
	                        unitList.getEpcUnits().add(whileStart);
	                        unitList.getEpcUnits().add(whileEnd);
	                     
	                        unitList.bulidRelationship(prefixUnit.getId(), whileStart.getId());
	                        unitList.bulidRelationship(whileStart.getId(), funcList.get(0).getId());
	                        unitList.bulidRelationship(funcList.get(funcList.size() - 1).getId(), whileEnd.getId());
	                        unitList.bulidRelationship(whileEnd.getId(), postfixUnit.getId());
	                    }
	                    for (int k = 1; k < funcList.size(); k++) {
	                        unitList.bulidRelationship(funcList.get(k - 1).getId(),funcList.get(k).getId());
	                    }
	                }
	            }
	            
	        }
	        return unitList.getEpcUnits();
	    }

	  

	    /**
	     * Polish the bpel models by breadth first.
	     * 
	     * @param unitList
	     *            The control unit list.
	     * @return The BPEL node list.
	     * @throws ParserConfigurationException 
	     * 
	     */
		
		
	    public  Document polishBPELModelsByBreadthFirst(
	            List<Epcunit> sourceList) throws ParserConfigurationException {
	    	
	    	DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc=db.newDocument();
			
			Epcunit andJoin=null;
			Element process=doc.createElement("bpel:process");
			process.setAttribute("name", sourceList.get(0).getName());
			process.setAttribute("suppressJoinFailure", "yes");
			process.setAttribute("targetNamespace", "http://centaury/bpel/sample");
			process.setAttribute("xmlns:bpel", "http://docs.oasis-open.org/wsbpel/2.0/process/executable");
			process.setAttribute("xmlns:tns", "http://centaury/bpel/sample");
			process.setAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
			
			doc.appendChild(process);
			
			
			Element eImport=doc.createElement("bpel:import");
			eImport.setAttribute("location", "sample.wsdl");
			eImport.setAttribute("namespace", "http://centaury/bpel/sample.wsdl");
			eImport.setAttribute("importType", "http://schemas.xmlsoap.org/wsdl/" );
			process.appendChild(eImport);
			
			Element partnerLinks=doc.createElement("bpel:partnerLinks");
			process.appendChild(partnerLinks);
			
			Element variables=doc.createElement("bpel:variables");
			process.appendChild(variables);
			
			Stack<Element> tag=new Stack<Element>(); 
			Element sequence=doc.createElement("bpel:sequence");
			sequence.setAttribute("name", "main");
			tag.push(sequence);
			    
			    sourceList = polishBPELModelsWithLoop(sourceList);
		    	Epcunits uList=new Epcunits();
				uList.setEpcUnits(sourceList);
		    	this.setUnitList(uList);

		       
		    	Hashtable<Epcunit,Integer> isTraversed=new Hashtable();//存储已访问的单元
		        Stack<Epcunit> stack = new Stack<Epcunit>();
		        Epcunit beginUnit = null;
		        int count = 0;
		        
		        
		        for (Epcunit temp:sourceList){
					isTraversed.put(temp,0);
				}
		        
		        for (Epcunit unit : unitList.getEpcUnits()) {
		            if (unit.getType()=="start") {
		                beginUnit = unit;
		                for (int n1:beginUnit.getNext()){
		                	 stack.push(unitList.findSourceDataById(n1));  //把后续结点放入栈中
		              }
		                break;
		            }
		        }
		        if (beginUnit == null) {
		            return null;
		        }
		        Element flow=null;  //and  flow
            	Element and=null;   //and 分支 sequence
            	Element eIf=null;   //xor or    if  elseif
            	Element or=null;    //xor or 分支sequence
            	Element whileStart=null;     //while 
            	Element whileSequence=null;    //while sequence
            	Element parent=null;
            	int split=0;
            	
		        // Access models by depth first.
		        while (!stack.empty()) {
		            Epcunit unit = stack.pop();
		        
		            if (unit.getNext()!= null && isTraversed.get(unit)!=1
		                    && unit.getNext().size() > 0) {
		                for (int n2:unit.getNext()) {
		                    stack.push(unitList.findSourceDataById(n2));
		                   
		                }
		            }        //如果还有后续并且此结点没有被访问过 存储后续结点
		            
		           
		            
		            if (unit.getType()=="connector") {
		                // Analyze unit to determine which element to
		                // add
		                if (unit.getName()=="and" ) {
		                	
		                	if (!stack.empty()){
		                		Epcunit and1=stack.pop(); 
			                	if (isTraversed.get(unit)!=1){   // 如果unit之前没访问过 
			                		split++;
			                		if (split==1){
			                			flow=doc.createElement("bpel:flow");
				                	    flow.setAttribute("name", "Flow"+(count++));
				                	    tag.push(flow);
				                	    isTraversed.put(unit,1);
			                		}
			                		else if (split==2){andJoin=and1;continue;}
			                		else continue;
			                	        
			                	}
			                	else {
			                	
			                			and=tag.pop();
				                		flow=tag.pop();
				                		tag.push(flow);
				                		
				                		flow.appendChild(and);
			                			
			                		
			                		
			                	}
			                    if (unitList.getEpcUnits().indexOf(and1)>unitList.getEpcUnits().indexOf(unit)) {
			                    	                    //如果栈中的元素的索引在后面说明还有未遍历的分支
			                    	stack.push(unit);
			                        and=doc.createElement("bpel:sequence");
			                        and.setAttribute("name", "Sequence" + (count++));
			                        tag.push(and);
			                    	
			                    	
			                    	stack.push(and1);
			                    	
			                    } else {
			                    	stack.push(and1);
			                    	flow=tag.pop();
			                    	parent=tag.pop();
			                    	tag.push(parent);
			                    	parent.appendChild(flow);  //把flow添加到最后
			                    	isTraversed.put(unit,0);
			                    	
			                    }
		                	}
		                	else {
		                		and=tag.pop();
		                		flow=tag.pop();
		                		flow.appendChild(and);
		                    	parent=tag.pop();
		                    	tag.push(parent);
		                    	parent.appendChild(flow);  //把flow添加到最后
		                    	if (split>1) {
		                    		split=0;
		                    		stack.push(andJoin);
		                    	}
		                	}
		                	
		                } else if (unit.getName()=="xor"
		                        || unit.getName()=="or") {
		                	
		                	if (!stack.empty()) {
		                		Epcunit or1=stack.pop(); 
		                		
		                		if (unitList.getEpcUnits().indexOf(or1)>unitList.getEpcUnits().indexOf(unit)) {
	        	                    //如果栈中的元素的索引在后面说明还有未遍历的分支
		                			
		                			if (isTraversed.get(unit)!=1){   // 如果unit之前没访问过 
				                	    eIf=doc.createElement("bpel:if");
				                	    eIf.setAttribute("name",  "If"+ (count++));
				                	    tag.push(eIf);
				                		isTraversed.put(unit,1);
				                	}    
				                	else if (isTraversed.get(unit)==1) {
				                		    or=tag.pop();
				                		    eIf=tag.pop();
				                		    eIf.appendChild(or);
				                		    parent=tag.pop();
				                		    tag.push(parent);
				                		    parent.appendChild(eIf);
				                    	    eIf=doc.createElement("bpel:elseif");
				                    	    tag.push(eIf);
				                     		                        }
		                			
			                		stack.push(unit); //把连接符push进站 标记分支结束
			                	    or=doc.createElement("bpel:sequence");
			                	    tag.push(or);
			                    	or.setAttribute("name", "Sequence" + (count++));
			                    	stack.push(or1);
			                    	eIf.appendChild(or);
			                		
			                	}   else {                //如果分支都遍历完后
			                		or=tag.pop();
		                		    eIf=tag.pop();
		                		    eIf.appendChild(or);
		                		    parent=tag.pop();
		                		    tag.push(parent);
		                		    parent.appendChild(eIf);
			                		stack.push(or1);
			                    }
			               	
		                	}
		                	else {                         //如果栈空 意味着 分支遍历完
		                		or=tag.pop();
	                		    eIf=tag.pop();
	                		    eIf.appendChild(or);
	                		    parent=tag.pop();
	                		    tag.push(parent);
	                		    parent.appendChild(eIf);
		                		
		                	}
		                }
		            }

		            // Analyze  unit to determine which element to add
		          
		            if (unit.getType()=="function") {  //如果是函数
		            	Element invoke=doc.createElement("bpel:invoke");
		            	invoke.setAttribute("name",unit.getName());
		            	invoke.setAttribute("partnerLink","");
		            	invoke.setAttribute("portType", "");
		                invoke.setAttribute("operation",unit.getName());
		                invoke.setAttribute("variable", "");
		                parent=tag.pop();
		                tag.push(parent);
		                parent.appendChild(invoke);
		                isTraversed.put(unit, 1);
		                                     
		            }  else if (unit.getType()== "while") {
		                
		                if (unit.getName()=="WHILE_START") {
		                	whileStart=doc.createElement("bpel:while");
		                	whileStart.setAttribute("name", "While"+ (count++));
		                	tag.push(whileStart);
		                   
		                    whileSequence=doc.createElement("bpel:sequence");
		                	whileSequence.setAttribute("name", "Sequence"+(count++));
		                	tag.push(whileSequence);
		                 
		                } else {
		                	
		                	whileSequence=tag.pop();
		                    whileStart=tag.pop();
                          	whileStart.appendChild(whileSequence);
                          	parent=tag.pop();
    		                tag.push(parent);
                          	parent.appendChild(whileStart);
		                }
		            } 
		                
		            }
		         process.appendChild(sequence);
		        
		        return doc;
			
	        // Replace loop while while.
	    	
	       
	    }

	    
	    
	    
	    public static void main(String[] args) throws TransformerException {
	       

	    	GenerateBpel g=new GenerateBpel();
	        
	                
	        Epcunits test;
			
				ParserEpc p=new ParserEpc();
				try {
					test = p.parse("E:/askForLeave-2012-04-22-09-20-17.epc");
					Document doc = g.polishBPELModelsByBreadthFirst(test.getEpcUnits());
					GenerateBpmn.domDocToFile(doc, "E:/test.xml", "UTF-8");
				} catch (SAXException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (ParserConfigurationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				
				
				
			}
	        
	       
	    }




